home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1993 / Internet Info CD-ROM (Walnut Creek) (1993).iso / networking / terms / kermit / b / ckmkey.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-30  |  24.1 KB  |  954 lines

  1. /* $Id: ckmkey.c,v 1.4 91/12/15 23:17:43 rick Exp $
  2.  * $Source: /uw/mackermit/RCS/ckmkey.c,v $
  3.  *------------------------------------------------------------------
  4.  * $Log:    ckmkey.c,v $
  5.  * Revision 1.4  91/12/15  23:17:43  rick
  6.  * ut9
  7.  * 
  8.  * Revision 1.3  91/10/03  12:43:08  rick
  9.  * UT(5)
  10.  * 
  11.  *------------------------------------------------------------------
  12.  * $Endlog$
  13.  */
  14.  
  15. /*
  16.  * CKMKEY.C
  17.  *
  18.  * This file contains all procedures and data related to the handling
  19.  * of key macros.
  20.  *
  21.  * Matthias Aebi, ECOFIN Research and Consulting, Ltd., Oct 1987
  22.  *
  23.  * Chaged 12/11/87 Paul Placeway @ Ohio State University: changed the
  24.  *  internal storage of a key macro from a C string to a Pascal string
  25.  *  (so that I could bind Control-Space to send ASCII NUL (0x00)
  26.  *
  27.  * Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New
  28.  * York.  Permission is granted to any individual or institution to use this
  29.  * software as long as it is not sold for profit.  This copyright notice must 
  30.  * be retained.  This software may not be included in commercial products 
  31.  * without written permission of Columbia University.
  32.  */
  33.  
  34. #include "ckcdeb.h"        /* Kermit definitions */
  35. #include "ckcker.h"        /* Kermit definitions */
  36.  
  37. #include "ckmdef.h"        /* Common Mac module definitions */
  38. #include "ckmres.h"        /* resource defs */
  39. #include "ckmptp.h"            /* ckm* Prototypes */
  40.  
  41.  
  42. /* KSET This structure tells for which key / modifier combinations */
  43. /* there is a special macro declaration. */
  44. /* MSET This structure holds all macrokey definitons in a packed */
  45. /* form. To be useful it has to be unpacked into a macrodefs     */
  46. /* structure. */
  47.  
  48. hmacrodefs macroshdl;
  49.  
  50. char keytable[512];
  51.  
  52. extern Handle gethdl ();
  53.  
  54.  
  55. /****************************************************************************/
  56. /* Look for a macrodefinition for theCode and return its table index if */
  57. /* found or -1 if not found */
  58. /****************************************************************************/
  59. short
  60. FindMacro (theCode)
  61. short theCode;
  62. {
  63.     short i;
  64.     short num;
  65.     macrodefs *macros;
  66.  
  67.     macros = *macroshdl;
  68.  
  69.     num = macros->numOfMacros;
  70.     for (i = 0; (i < num) && (macros->mcr[i].code != theCode); i++);
  71.  
  72.     if (i >= num)
  73.     return (-1);
  74.     else
  75.     return (i);
  76. }                /* FindMacro */
  77.  
  78.  
  79.  
  80. /****************************************************************************/
  81. /* Set theCode at theIndex to -1 which means this entry is empty. Release */
  82. /* the memory block occupied to save the macrostring if necessary */
  83. /****************************************************************************/
  84. DeleteMacro (theIndex)
  85. short theIndex;
  86. {
  87.     macrodefs *macros;
  88.  
  89.     macros = *macroshdl;
  90.  
  91.     macros->mcr[theIndex].code = -1;
  92.     if (macros->mcr[theIndex].len > 4)    /* release memory block if there is
  93.                      * one */
  94.     DisposPtr ((Ptr) macros->mcr[theIndex].macro);
  95. }                /* DeleteMacro */
  96.  
  97.  
  98.  
  99. /****************************************************************************/
  100. /* Add a new macro table entry at the end and return its index */
  101. /****************************************************************************/
  102. short
  103. NewMacro ()
  104. {
  105.     macrodefs *macros;
  106.     long hsize;
  107.     short num;
  108.  
  109.     macros = *macroshdl;
  110.     macros->numOfMacros++;
  111.     num = macros->numOfMacros;
  112.  
  113.     hsize = GetHandleSize ((Handle) macroshdl);
  114.     if ((num * sizeof (macrorec) + MacroBaseSize) > hsize) {
  115.     /* allocate room for 10 more definitions */
  116.     HUnlock ((Handle) macroshdl);
  117.     SetHandleSize ((Handle) macroshdl, hsize + 10 * sizeof (macrorec));
  118.     HLock ((Handle) macroshdl);
  119.     }
  120.     /* init the code field to -1 (empty) */
  121.     macros = *macroshdl;
  122.     macros->mcr[--num].code = -1;
  123.  
  124.     return (num);
  125. }                /* NewMacro */
  126.  
  127.  
  128.  
  129. /****************************************************************************/
  130. /* Enter theCode and theStr into the (empty!) entry at tabIndex. SetMacro  */
  131. /* does    not release a previously existing string. Do this with DeleteMacro */
  132. /* first. */
  133. /****************************************************************************/
  134. SetMacro (theIndex, theCode, theFlags, theStr)
  135. short theIndex;
  136. short theCode;
  137. char *theFlags;
  138. char *theStr;            /* PWP: note: this is now a Pascal string */
  139. {
  140.     macrodefs *macros;
  141.     short slen;
  142.     Ptr sptr;
  143.  
  144.     macros = *macroshdl;
  145.  
  146.     if (macros->mcr[theIndex].code != -1)    /* check for free entry */
  147.     printerr ("snh SetMacro", 0);
  148.  
  149.     macros->mcr[theIndex].code = theCode;
  150.     macros->mcr[theIndex].flags = *theFlags;
  151.     if (*theFlags) {    /* (PWP) save a bit of space: if flags, then no string */
  152.     macros->mcr[theIndex].macro = 0;
  153.     macros->mcr[theIndex].len = 1;
  154.     } else {
  155.     slen = theStr[0] + 1;    /* PWP: was ... = strlen(theStr); */
  156.     if (slen > 4) {
  157.         sptr = NewPtr (slen);
  158.         BlockMove (theStr, sptr, slen);
  159.                 /* PWP: yes, we save the length too */
  160.         macros->mcr[theIndex].macro = (long) sptr;
  161.     } else {
  162.         BlockMove (theStr, (Ptr) ¯os->mcr[theIndex].macro, slen);
  163.     }
  164.     macros->mcr[theIndex].len = slen;
  165.     }
  166. }                /* SetMacro */
  167.  
  168.  
  169.  
  170. /****************************************************************************/
  171. /* Save theStr as macrostring for the code. Reuse any empty table entires */
  172. /****************************************************************************/
  173. InsertMacro (theCode, theFlags, theStr)
  174. short theCode;
  175. char *theFlags;
  176. char *theStr;            /* PWP: a Pascal string */
  177. {
  178.     short idx;
  179.  
  180.     HLock ((Handle) macroshdl);
  181.  
  182.     if (FindMacro (theCode) >= 0)    /* does the entry exist already */
  183.     printerr ("snh InsertMacro", 0);
  184.  
  185.     idx = FindMacro (-1);    /* look for a free entry */
  186.     if (idx < 0)        /* create a new free entry if none is
  187.                  * available */
  188.     idx = NewMacro ();
  189.     SetMacro (idx, theCode, theFlags, theStr);
  190.  
  191.     HUnlock ((Handle) macroshdl);
  192. }                /* InsertMacro */
  193.  
  194.  
  195.  
  196. /****************************************************************************/
  197. /* Remove the macro definition from the table and mark its entry as empty */
  198. /****************************************************************************/
  199. RemoveMacro (theCode)
  200. short theCode;
  201. {
  202.     short idx;
  203.  
  204.     HLock ((Handle) macroshdl);
  205.  
  206.     idx = FindMacro (theCode);    /* look for the entry */
  207.     if (idx >= 0)
  208.     DeleteMacro (idx);    /* delete it if we found it */
  209.     else
  210.     printerr ("snh RemoveMacro", 0);
  211.  
  212.     HUnlock ((Handle) macroshdl);
  213. }                /* RemoveMacro */
  214.  
  215.  
  216.  
  217. /****************************************************************************/
  218. /* Replace the macro definition in the table */
  219. /****************************************************************************/
  220. ReplaceMacro (theCode, theFlags, theStr)
  221. short theCode;
  222. char *theFlags;
  223. char *theStr;
  224. {
  225.     short idx;
  226.  
  227.     HLock ((Handle) macroshdl);
  228.  
  229.     idx = FindMacro (theCode);    /* look for the entry */
  230.     if (idx >= 0) {
  231.     DeleteMacro (idx);    /* delete it if we found it */
  232.     /* reuse it immediately */
  233.     SetMacro (idx, theCode, theFlags, theStr);
  234.     } else
  235.     printerr ("snh ReplaceMacro", 0);
  236.  
  237.     HUnlock ((Handle) macroshdl);
  238. }                /* ReplaceMacro */
  239.  
  240.  
  241.  
  242. /****************************************************************************/
  243. /* Get the macro string for theCode from the table */
  244. /****************************************************************************/
  245. GetMacro (theCode, theFlags, theStr)
  246. short theCode;
  247. char *theFlags;
  248. char *theStr;
  249. {
  250.     short idx;
  251.     macrodefs *macros;
  252.     short slen;
  253.     Ptr sptr;
  254.  
  255.     HLock ((Handle) macroshdl);
  256.     macros = *macroshdl;
  257.  
  258.     idx = FindMacro (theCode);    /* look for the entry */
  259.     if (idx >= 0) {
  260.     slen = macros->mcr[idx].len;
  261.  
  262.     if (slen > 4)
  263.         sptr = (Ptr) macros->mcr[idx].macro;
  264.     else
  265.         sptr = (Ptr) ¯os->mcr[idx].macro;
  266.  
  267.     BlockMove (sptr, theStr, slen);
  268.     /* *(theStr + slen) = '\0'; */
  269.  
  270.     *theFlags = macros->mcr[idx].flags;
  271.     } else
  272.     printerr ("snh GetMacro", theCode);
  273.  
  274.     HUnlock ((Handle) macroshdl);
  275. }                /* GetMacro */
  276.  
  277.  
  278.  
  279. /****************************************************************************/
  280. /* dipose all macro strings */
  281. /****************************************************************************/
  282. DisposeMacros ()
  283. {
  284.     short i;
  285.     short num;
  286.     macrodefs *macros;
  287.  
  288.     HLock ((Handle) macroshdl);
  289.     macros = *macroshdl;
  290.  
  291.     num = macros->numOfMacros;
  292.     for (i = 0; i < num; i++)
  293.     if (macros->mcr[i].code != -1)
  294.         DeleteMacro (i);
  295.  
  296.     macros->numOfMacros = 0;
  297.     HUnlock ((Handle) macroshdl);
  298. }                /* DisposeMacros */
  299.  
  300.  
  301.  
  302. /****************************************************************************/
  303. /* compress '\' expressions */
  304. /****************************************************************************/
  305. EncodeString (s, flags)
  306. char *s;            /* PWP: takes a C string, returns a Pascal
  307.                  * string. */
  308. char *flags;
  309. {
  310.     register char *t, *b;
  311.     register int v, i;
  312.     char buf[256];
  313.  
  314.     *flags = '\0';        /* no flags set */
  315.  
  316.     if ((strcmp (s, "\\break") == 0) ||
  317.     (strcmp (s, "\\shortbreak") == 0)) {
  318.     *flags = shortBreak;
  319.     return;
  320.     } else
  321.     if (strcmp (s, "\\longbreak") == 0) {
  322.     *flags = longBreak;
  323.     return;
  324.     } else
  325.     if (strcmp (s, "\\leftarrow") == 0) {
  326.     *flags = leftArrowKey;
  327.     return;
  328.     } else
  329.     if (strcmp (s, "\\rightarrow") == 0) {
  330.     *flags = rightArrowKey;
  331.     return;
  332.     } else
  333.     if (strcmp (s, "\\uparrow") == 0) {
  334.     *flags = upArrowKey;
  335.     return;
  336.     } else
  337.     if (strcmp (s, "\\downarrow") == 0) {
  338.     *flags = downArrowKey;
  339.     return;
  340.     } else
  341.     if (strcmp (s, "\\pf1") == 0) {
  342.     *flags = keypf1;
  343.     return;
  344.     } else
  345.     if (strcmp (s, "\\pf2") == 0) {
  346.     *flags = keypf2;
  347.     return;
  348.     } else
  349.     if (strcmp (s, "\\pf3") == 0) {
  350.     *flags = keypf3;
  351.     return;
  352.     } else
  353.     if (strcmp (s, "\\pf4") == 0) {
  354.     *flags = keypf4;
  355.     return;
  356.     } else
  357.     if (strcmp (s, "\\enter") == 0) {
  358.     *flags = keyenter;
  359.     return;
  360.     } else
  361.     if ((strncmp (s, "\\keypad", 7) == 0) && (s[8] == '\0')) {
  362.     if ((s[7] >= ',') && (s[7] <= '9')) {
  363.         *flags = keycomma + (s[7] - ',');
  364.     }
  365.     return;
  366.     }
  367.     *(s + 255) = '\0';
  368.     b = s;
  369.     t = buf;
  370.  
  371.     while (*s != '\0') {
  372.     if (*s != '\\')
  373.         *t = *s++;
  374.     else if isdigit(*++s) {        /* if \digits */
  375.         /* the current char was a backslash */
  376.         for (i = 0, v = 0; i < 3; i++) {
  377.         /* only do the first 3 digits: \0335 -> ^[5 */
  378.         if (!isdigit(*s))
  379.             break;
  380.         v = (8 * v) + (int) *s++ - (int) '0';
  381.         }
  382.         *t = (char) v % 256;
  383.     } else {
  384.         switch (*s) {
  385.           case 'b':    /* backspace */
  386.         *t = '\010';
  387.         break;
  388.  
  389.           case 't':    /* tab */
  390.         *t = '\011';
  391.         break;
  392.  
  393.           case 'n':    /* newline -- linefeed */
  394.         *t = '\012';
  395.         break;
  396.  
  397.           case 'f':    /* formfeed */
  398.         *t = '\014';
  399.         break;
  400.  
  401.           case 'r':    /* return */
  402.         *t = '\015';
  403.         break;
  404.  
  405.           case '^':    /* \^c --> control-C */
  406.         s++;
  407.         if (*s == '?')
  408.             *t = '\177';/* special case */
  409.         else
  410.             *t = (*s & 037);
  411.         break;
  412.  
  413.           default:
  414.         *t = *s;
  415.         }
  416.         s++;
  417.     }
  418.     t++;
  419.     }
  420.     b[0] = (char) (t - buf);    /* PWP: the length */
  421.     BlockMove (buf, &b[1], b[0]);    /* copy the new string in */
  422. }                /* EncodeString */
  423.  
  424.  
  425.  
  426. /****************************************************************************/
  427. /* Decode the pascal string into a C string with '\' notation */
  428. /****************************************************************************/
  429. DecodeString (s, flags)
  430. char *s;            /* takes a Pascal string, returns a C string */
  431. char flags;            /* PWP: note! not a pointer */
  432. {
  433.     register unsigned char ch;
  434.     register char *tp;
  435.     char t[256];        /* PWP: actually, this probably won't
  436.                  * overflow 256, but be safe */
  437.     register int i, j;
  438.  
  439.     switch (flags) {
  440.       case shortBreak:
  441.     strcpy (s, "\\break");
  442.     return;
  443.  
  444.       case longBreak:
  445.     strcpy (s, "\\longbreak");
  446.     return;
  447.  
  448.       case leftArrowKey:
  449.     strcpy (s, "\\leftarrow");
  450.     return;
  451.  
  452.       case rightArrowKey:
  453.     strcpy (s, "\\rightarrow");
  454.     return;
  455.     
  456.       case upArrowKey:
  457.     strcpy (s, "\\uparrow");
  458.     return;
  459.     
  460.       case downArrowKey:
  461.     strcpy (s, "\\downarrow");
  462.     return;
  463.     
  464.       case keypf1:
  465.       case keypf2:
  466.       case keypf3:
  467.       case keypf4:
  468.     strcpy (s, "\\pf");
  469.     s[3] = flags - keypf1 + '1';
  470.     s[4] = '\0';
  471.     return;
  472.     
  473.       case keyenter:
  474.     strcpy (s, "\\enter");
  475.     return;
  476.     
  477.       case keycomma:
  478.       case keyminus:
  479.       case keyperiod:
  480.       /* there is no keyslash */
  481.       case key0:
  482.       case key1:
  483.       case key2:
  484.       case key3:
  485.       case key4:
  486.       case key5:
  487.       case key6:
  488.       case key7:
  489.       case key8:
  490.       case key9:
  491.     strcpy (s, "\\keypad");
  492.     s[7] = flags - keycomma + ',';
  493.     s[8] = '\0';
  494.     return;
  495.     }
  496.  
  497.     tp = t;
  498.     for (i = 1; i <= s[0]; i++) {    /* PWP: step through a Pascal string */
  499.     ch = s[i];
  500.     if ((ch < ' ') || (ch > 126)) {
  501.         *tp++ = '\\';
  502.         j = (long) ch & 0377;    /* mask of sign extension */
  503.         *tp++ = (j / 0100) + '0';    /* 64s digit */
  504.         j &= 077;
  505.         *tp++ = (j / 010) + '0';    /* 8s digit */
  506.         j &= 07;
  507.         *tp++ = j + '0';    /* 1s digit */
  508.     } else if (ch == '\\') {
  509.         *tp++ = '\\';
  510.         *tp++ = '\\';
  511.     } else
  512.         *tp++ = ch;
  513.     }
  514.     *tp = '\0';
  515.     t[255] = '\0';        /* be extra safe */
  516.     strcpy (s, t);        /* copy it into place */
  517. }                /* DecodeString */
  518.  
  519.  
  520.  
  521. #define KeyPressed 2        /* dummy item. returned when a key is pressed */
  522. #define myKeyCodeMask 0x7F00
  523. #define keyModifierMask 0x1F00
  524. short lastCode;
  525.  
  526. /****************************************************************************/
  527. /* return KeyPressed and TRUE if a keyevent happened */
  528. /****************************************************************************/
  529. pascal Boolean
  530. keyfilter (theDialog, theEvent, itemHit)
  531. DialogPtr theDialog;
  532. EventRecord *theEvent;
  533. short *itemHit;
  534. {
  535.     Boolean retVal;
  536.     char modstr[256];
  537.     char theChar[3];
  538.     char codeStr[5];
  539.  
  540.     retVal = (theEvent->what == keyDown);
  541.     if (retVal) {
  542.     *itemHit = KeyPressed;
  543.  
  544.     /* show modifiers pressed */
  545.     *modstr = '\0';
  546.     if (theEvent->modifiers & shiftKey)
  547.         strcat (modstr, " shift");
  548.     if (theEvent->modifiers & alphaLock)
  549.         strcat (modstr, " lock");
  550.     if (theEvent->modifiers & optionKey)
  551.         strcat (modstr, " option");
  552.  
  553. #ifndef controlKey
  554. #define controlKey 4096        /* PWP: hack for beta MPW C */
  555. #endif
  556.  
  557.     if (theEvent->modifiers & controlKey)
  558.         strcat (modstr, " control");
  559.     if (theEvent->modifiers & cmdKey)
  560.         strcat (modstr, " command");
  561.  
  562.     strcpy (theChar, "  ");
  563.     *(theChar + 1) = (theEvent->message & charCodeMask);
  564.     strcat (modstr, theChar);
  565.  
  566.     lastCode = ((theEvent->message & myKeyCodeMask) >> 8) +
  567.         ((theEvent->modifiers & keyModifierMask) >> 1);
  568.     NumToString (lastCode, codeStr);
  569.     p2cstr(codeStr);
  570.     strcat (modstr, "  (");
  571.     strcat (modstr, codeStr);
  572.     strcat (modstr, ")");
  573.  
  574.     if (BitTst (keytable, lastCode))
  575.         strcat (modstr, " bound to:");
  576.     else
  577.         strcat (modstr, " [unbound]");
  578.  
  579.     c2pstr(modstr);
  580.     SetIText (gethdl (KY_MODIFIER, theDialog), modstr);
  581.     }
  582.     return (retVal);
  583. }                /* keyfilter */
  584.  
  585.  
  586.  
  587. #define HelpBtn 3
  588.  
  589. /****************************************************************************/
  590. /* runs the set key macros dialog */
  591. /****************************************************************************/
  592. keymacros ()
  593. {
  594.     DialogPtr macrodlg;
  595.     DialogPtr macro2dlg;
  596.     short itemhit;
  597.     Str255 keystr;
  598.     char flags;
  599.  
  600.     macrodlg = GetNewDialog (KEYBOXID, NILPTR, (WindowPtr) - 1);
  601.  
  602.     for (;;) {
  603.     SetIText (gethdl(KY_MODIFIER, macrodlg), "\pPress the key to program");
  604.     ModalDialog (keyfilter, &itemhit);
  605.  
  606.     switch (itemhit) {
  607.       case OKBtn:        /* finish up */
  608.         DisposDialog (macrodlg);    /* finished with the dialog */
  609.         return;        /* return */
  610.  
  611.       case KeyPressed:    /* fall in from above */
  612.         macro2dlg = GetNewDialog (KEY2BOXID, NILPTR, (WindowPtr) - 1);
  613.         circleOK(macro2dlg);
  614.  
  615.         /* display the current macrostring if there is one */
  616.         if (BitTst (keytable, lastCode)) {
  617.         GetMacro (lastCode, &flags, keystr);
  618.         DecodeString (keystr, flags);    /* decode invisible
  619.                          * characters */
  620.         c2pstr(keystr);
  621.         SetIText (gethdl (KY_TEXT, macro2dlg), keystr);
  622.         SelIText(macro2dlg, KY_TEXT, 0, 32767);
  623.         }
  624.         itemhit = 0;
  625.         while (itemhit == 0) {
  626.         ModalDialog ((ModalFilterProcPtr) NILPROC, &itemhit);
  627.  
  628.         switch (itemhit) {
  629.           case OKBtn:    /* finish up */
  630.             GetIText (gethdl (KY_TEXT, macro2dlg), keystr);
  631.             p2cstr(keystr);
  632.             EncodeString (keystr, flags);    /* encode '\'
  633.                              * expressions */
  634.             if (BitTst (keytable, lastCode))
  635.             if (strlen (keystr) > 0)
  636.                 ReplaceMacro (lastCode, flags, keystr);
  637.             else {
  638.                 RemoveMacro (lastCode);
  639.                 BitClr (keytable, lastCode);
  640.             }
  641.             else if (strlen (keystr) > 0) {
  642.             InsertMacro (lastCode, flags, keystr);
  643.             BitSet (keytable, lastCode);
  644.             }
  645.           case QuitBtn:
  646.             DisposDialog (macro2dlg);    /* finished with the dialog */
  647.             break;
  648.  
  649.           case KY_HELP:
  650.             itemhit = Alert (ALERT_HELP, (ModalFilterProcPtr) NILPROC);
  651.  
  652.           default:
  653.             itemhit = 0;
  654.         }
  655.         }
  656.     }
  657.     }
  658. }                /* keymacros */
  659.  
  660.  
  661.  
  662. modrec modtable[NUMOFMODS];
  663.  
  664. /****************************************************************************/
  665. /* handle the modifier dialog */
  666. /****************************************************************************/
  667. keymoddialog ()
  668. {
  669.     DialogPtr moddlg;
  670.     short itemhit;
  671.     modrec tmodtable[NUMOFMODS];/* temporary copy of modtable */
  672.     short i;
  673.     short ignType;
  674.     Handle ignHdl;
  675.     Rect box;
  676.     char theStr[256];
  677.     GrafPtr savePort;
  678.  
  679.     GetPort (&savePort);
  680.  
  681.     moddlg = GetNewDialog (MODBOXID, NILPTR, (WindowPtr) - 1);
  682.     circleOK(moddlg);
  683.     SetPort (moddlg);
  684.  
  685.     for (i = 0; i < NUMOFMODS; i++)
  686.     tmodtable[i] = modtable[i];    /* make a temporary copy */
  687.  
  688.     /* draw the gray lines */
  689.     for (i = MOD_LIN1; i <= MOD_LINL; i++) {
  690.     GetDItem (moddlg, i, &ignType, &ignHdl, &box);
  691.     FillRect (&box, qd.gray);
  692.     }
  693.  
  694.     /* set the texts in the edit fields */
  695.     for (i = 0; i < NUMOFMODS; i++) {
  696.     /* PWP: these are saved as pascal strings now... */
  697.     theStr[0] = 0;        /* be double extra safe */
  698.     BlockMove (tmodtable[i].prefix, theStr, (tmodtable[i].prefix[0] + 1));
  699.     DecodeString (theStr, (char) 0);
  700.     c2pstr(theStr);
  701.     SetIText (gethdl (i + MOD_PRF1, moddlg), theStr);
  702.     }
  703.  
  704.     /* set the checkboxes according to the bits set */
  705.     for (i = MOD_CHK1; i <= MOD_CHKL; i++)
  706.     SetCtlValue (getctlhdl (i, moddlg),
  707.              (tmodtable[(i - MOD_CHK1) / 9].modbits &
  708.               (1 << ((i - MOD_CHK1) % 9))) ? btnOn : btnOff);
  709.  
  710.     /* loop till ok or cancel is pressed */
  711.     for (;;) {
  712.     ModalDialog ((ModalFilterProcPtr) NILPROC, &itemhit);
  713.     if (itemhit == OKBtn) {
  714.         for (i = 0; i < NUMOFMODS; i++) {
  715.         GetIText (gethdl (i + MOD_PRF1, moddlg), theStr);
  716.         p2cstr(theStr);
  717.         EncodeString (theStr);
  718.         if ((unsigned) (theStr[0]) > 19) /* Limit the length of
  719.                           * the thing */
  720.             theStr[0] = 19;
  721.         BlockMove (theStr, tmodtable[i].prefix, 20);
  722.         }
  723.  
  724.         /* write the temporary copy back */
  725.         for (i = 0; i < NUMOFMODS; i++)
  726.         modtable[i] = tmodtable[i];
  727.  
  728.         UpdateOptKey(1);        /* make Option key processing right */
  729.     }
  730.     if ((itemhit == OKBtn) || (itemhit == QuitBtn)) {
  731.         DisposDialog (moddlg);    /* finished with the dialog */
  732.         SetPort (savePort);
  733.         return;
  734.     }
  735.     if (itemhit == MOD_HELP) {
  736.         itemhit = Alert (ALERT_MODHELP, (ModalFilterProcPtr) NILPROC);
  737.         /* draw the gray lines again */
  738.         for (i = MOD_LIN1; i <= MOD_LINL; i++) {
  739.         GetDItem (moddlg, i, &ignType, &ignHdl, &box);
  740.         FillRect (&box, qd.gray);
  741.         }
  742.     }
  743.     if (itemhit <= MOD_CHKL) {    /* is it a check box ? */
  744.         tmodtable[(itemhit - MOD_CHK1) / 9].modbits
  745.         ^= (1 << ((itemhit - MOD_CHK1) % 9));
  746.         SetCtlValue (getctlhdl (itemhit, moddlg),
  747.              (tmodtable[(itemhit - MOD_CHK1) / 9].modbits &
  748.               (1 << ((itemhit - MOD_CHK1) % 9))) ? btnOn : btnOff);
  749.     }
  750.     }
  751. }                /* keymoddialog */
  752.  
  753.  
  754.  
  755. /****************************************************************************/
  756. /* load and unpack the key macro tables */
  757. /****************************************************************************/
  758. loadkset ()
  759. {
  760.     Handle ktab;
  761.     char *k;
  762.     int i;
  763.     THz curZone;
  764.  
  765.     /* load the bit table */
  766.     ktab = GetResource (KSET_TYPE, KSVER);
  767.  
  768.     if (ktab == (Handle) NIL)
  769.     printerr ("Could not load the key macros (KSET) [old version?]", 0);
  770.  
  771.     if ((ktab == (Handle) NIL) || (GetHandleSize (ktab) == 0)) {
  772.     /* init the keytable with zeroes if ktab is empty or not available */
  773.     /* ktab is empty in the resource fork of the program itself */
  774.     k = keytable;
  775.     for (i = 1; i <= sizeof (keytable); i++)
  776.         *k++ = '\0';
  777.     return;
  778.     }
  779.     HLock (ktab);
  780.     BlockMove (*ktab, keytable, sizeof (keytable));
  781.     HUnlock (ktab);
  782.     curZone = GetZone();        /* as per John Norstad's (Disinfectant) */
  783.     SetZone(HandleZone(ktab));    /* "Toolbox Gotchas" */
  784.     ReleaseResource(ktab);
  785.     SetZone(curZone);
  786. }                /* loadkset */
  787.  
  788.  
  789.  
  790. /****************************************************************************/
  791. /* load and unpack the key macro table */
  792. /****************************************************************************/
  793. loadmset ()
  794. {
  795.     short i;
  796.     short idx;
  797.     short num;
  798.     short theCode;
  799.     Handle mtab;
  800.     char *src;
  801.     char flags;
  802.     THz curZone;
  803.  
  804.     DisposeMacros ();        /* release all macro strings */
  805.  
  806.     /* load the bit table */
  807.     mtab = GetResource (MSET_TYPE, KMVER);
  808.  
  809.     if (mtab == (Handle) NIL) {
  810.     printerr ("Could not load the key macros (MSET) [old version?]", 0);
  811.     return;
  812.     }
  813.     HLock (mtab);
  814.     HLock ((Handle) macroshdl);
  815.     src = *mtab;
  816.  
  817.     /* load the modifier information */
  818.     BlockMove (src, (Ptr) modtable, sizeof (modtable));
  819.     src += sizeof (modtable);
  820.  
  821.     UpdateOptKey(1);        /* make Option key processing right */
  822.  
  823.     /* get the number of macro key definitions */
  824.     BlockMove (src, (Ptr) &num, sizeof (num));
  825.     src += sizeof (num);
  826.  
  827.     for (i = 0; i < num; i++) {
  828.     /* Get the code */
  829.     BlockMove (src, (Ptr) &theCode, sizeof (theCode));
  830.     src += sizeof (theCode);
  831.  
  832.     /* Get the flags */
  833.     flags = *src++;
  834.  
  835.     /* Get the string */
  836.     /* p2cstr(src);  -- PWP: it allready is a pascal string! */
  837.     idx = NewMacro ();    /* create a new free entry */
  838.     SetMacro (idx, theCode, &flags, src);
  839.     src += src[0] + 1;    /* PWP: was strlen */
  840.     }
  841.  
  842.     HUnlock ((Handle) macroshdl);
  843.     HUnlock (mtab);
  844.     curZone = GetZone();        /* as per John Norstad's (Disinfectant) */
  845.     SetZone(HandleZone(mtab));    /* "Toolbox Gotchas" */
  846.     ReleaseResource(mtab);
  847.     SetZone(curZone);
  848. }                /* loadmset */
  849.  
  850.  
  851.  
  852. /****************************************************************************/
  853. /* save the key macro bit table */
  854. /****************************************************************************/
  855. savekset ()
  856. {
  857.     Handle ktab;
  858.  
  859.     ktab = NewHandle (sizeof (keytable));
  860.  
  861.     if (ktab == (Handle) NIL) {
  862.     printerr ("Could not save the key macros (KSET)", 0);
  863.     return;
  864.     }
  865.     HLock (ktab);
  866.     BlockMove (keytable, *ktab, sizeof (keytable));
  867.     HUnlock (ktab);
  868.     AddResource (ktab, KSET_TYPE, KSVER, "");
  869. }                /* savekset */
  870.  
  871.  
  872.  
  873. /****************************************************************************/
  874. savemset ()
  875. /****************************************************************************/
  876. /* pack and save the key macro table */
  877. {
  878.     short i;
  879.     short num;
  880.     short leng;
  881.     short count;
  882.     short theCode;
  883.     int totalLen;
  884.     char *dest;
  885.     Ptr src;
  886.     Handle mtab;
  887.     macrodefs *macros;
  888.  
  889.     HLock ((Handle) macroshdl);
  890.     macros = *macroshdl;
  891.  
  892.     num = macros->numOfMacros;
  893.     totalLen = 0;
  894.     count = 0;
  895.  
  896.     /* calculate the sum of the string lengths of all active table entries */
  897.     for (i = 0; i < num; i++)
  898.     if (macros->mcr[i].code != -1) {
  899.         totalLen += macros->mcr[i].len;
  900.         count++;
  901.     };
  902.  
  903.     /* add the length for keycode and length  */
  904.     /* information and the number of entries  */
  905.     totalLen += count * (sizeof (macrorec) - sizeof (long)) + MacroBaseSize;
  906.     mtab = NewHandle (totalLen);
  907.     if (mtab == (Handle) NIL) {
  908.     printerr ("Could not save the key macros (MSET)", 0);
  909.     return;
  910.     }
  911.     HLock (mtab);
  912.     dest = *mtab;
  913.  
  914.     /* save the modifier information */
  915.     BlockMove ((Ptr) modtable, dest, sizeof (modtable));
  916.     dest += sizeof (modtable);
  917.  
  918.     /* save the number of key macros */
  919.     BlockMove ((Ptr) &num, dest, sizeof (num));
  920.     dest += sizeof (num);
  921.  
  922.     /* save the whole rest of the table */
  923.     for (i = 0; i < num; i++) {
  924.     theCode = macros->mcr[i].code;
  925.     if (theCode != -1) {
  926.         /* save the code number */
  927.         BlockMove ((Ptr) &theCode, dest, sizeof (theCode));
  928.         dest += sizeof (theCode);
  929.  
  930.         /* save the flags */
  931.         leng = macros->mcr[i].len;
  932.         *dest++ = macros->mcr[i].flags;
  933.  
  934.         /* save the string length (1 byte!) */
  935.         /* PWP: nope! it's allready a Pascal string */
  936.         /* *dest++ = macros->mcr[i].len; */
  937.  
  938.         /* save the macro string */
  939.         if (leng > 4)
  940.         src = (Ptr) macros->mcr[i].macro;
  941.                 /* the address is stored here */
  942.         else
  943.         src = (Ptr) ¯os->mcr[i].macro;
  944.         BlockMove (src, dest, leng);
  945.         dest += leng;
  946.     }
  947.     }
  948.  
  949.     HUnlock (mtab);
  950.     HUnlock ((Handle) macroshdl);
  951.  
  952.     AddResource (mtab, MSET_TYPE, KMVER, "");
  953. }                /* savemset */
  954.